package com.steel.yfmall.cloud.assistant.view.impl;

import com.alibaba.fastjson.JSONObject;
import com.steel.yfmall.cloud.assistant.utils.zg.ZgViewUtil;
import com.steel.yfmall.cloud.assistant.view.PostalCodeBeanService;
import com.steel.yfmall.cloud.assistant.zg.ZgSOService;
import com.steel.yfmall.cloud.assistant.dto.para.view.ParaPostalCodeBean;
import com.steel.yfmall.cloud.assistant.dto.zg.SynZgResult;
import com.steel.yfmall.cloud.assistant.dto.zg.ZgSOResultBean;
import com.steel.yfmall.cloud.assistant.dto.zg.ZgViewBean;
import com.steel.yfmall.cloud.assistant.po.view.PostalCodeBean;
import com.steel.yfmall.cloud.assistant.po.view.PostalCodeBeanExample;
import com.steel.yfmall.cloud.assistant.po.view.PostalCodeBeanExample.Criteria;
import com.steel.yfmall.cloud.assistant.view.mapper.PostalCodeBeanMapper;
import com.steel.yfmall.cloud.components.utils.base.APIMsgBean;
import com.steel.yfmall.cloud.components.utils.base.Pages;
import com.steel.yfmall.cloud.components.utils.base.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author jia chang bao
 * @date 2020/11/9 14:03
 */
@Service
@Slf4j
public class PostalCodeBeanServiceImpl implements PostalCodeBeanService {

    @Resource
    PostalCodeBeanMapper postalCodeBeanMapper;

    @Resource
    private ZgSOService zgSOService;

    /**
     * 查询省市县邮政编码总条数
     *
     * @param paraPostalCodeBean 查询省市县邮政编码业务条件
     * @return 总条数
     */
    @Override
    public long getPostalCodeCount(ParaPostalCodeBean paraPostalCodeBean) {
        PostalCodeBeanExample postalCodeBeanExample = new PostalCodeBeanExample();
        Criteria criteria = postalCodeBeanExample.createCriteria();
        //判断入参对象是否为空
        if (!ObjectUtils.isEmpty(paraPostalCodeBean)) {
            getSearchData(criteria, paraPostalCodeBean);
        }
        return postalCodeBeanMapper.countByExample(postalCodeBeanExample);
    }

    /**
     * 分页查询查询省市县邮政编码（分页）
     *
     * @param paraPostalCodeBean 查询省市县邮政编码业务条件
     * @return 分页结果
     */
    @Override
    public Pages<PostalCodeBean> getPostalCodeOfPage(ParaPostalCodeBean paraPostalCodeBean) {
        Pages<PostalCodeBean> returnBean = new Pages<>();
        //判断是否有参数
        if (ObjectUtils.isEmpty(paraPostalCodeBean)) {
            return returnBean;
        }
        PostalCodeBeanExample postalCodeBeanExample = new PostalCodeBeanExample();
        Criteria criteria = postalCodeBeanExample.createCriteria();

        getSearchData(criteria, paraPostalCodeBean);
        //设置分页信息
        long result_count_int = postalCodeBeanMapper.countByExample(postalCodeBeanExample);
        returnBean.paging(paraPostalCodeBean.getCurrentPage(), paraPostalCodeBean.getPageSize(), result_count_int);
        postalCodeBeanExample.limit(returnBean.getStartPosition(), paraPostalCodeBean.getPageSize());
        //判断是否有排序
        if (StringUtils.isNotBlank(paraPostalCodeBean.getOrderByValue())) {
            postalCodeBeanExample.setOrderByClause(paraPostalCodeBean.getOrderByValue());
        }
        //分页结果封装
        List<PostalCodeBean> reachRegionBeans = postalCodeBeanMapper.selectByExample(postalCodeBeanExample);
        returnBean.setList(reachRegionBeans);
        return returnBean;
    }

    /**
     * 根据条件查询省市县邮政编码（不分页）
     *
     * @param paraPostalCodeBean 查询省市县邮政编码业务条件
     * @return 不分页结果
     */
    @Override
    public List<PostalCodeBean> getPostalCodeOfList(ParaPostalCodeBean paraPostalCodeBean) {
        //当条件为空时返回空
        if (ObjectUtils.isEmpty(paraPostalCodeBean)) {
            return null;
        }
        PostalCodeBeanExample postalCodeBeanExample = new PostalCodeBeanExample();
        Criteria criteria = postalCodeBeanExample.createCriteria();
        getSearchData(criteria, paraPostalCodeBean);

        List<PostalCodeBean> reachRegionBeans = postalCodeBeanMapper.selectByExample(postalCodeBeanExample);
        return reachRegionBeans;
    }

    /**
     * 新增单条省市县邮政编码
     *
     * @param postalCodeBean 省市县邮政编码业务条件
     * @return 受影响行数
     */
    @Override
    public int addPostalCode(PostalCodeBean postalCodeBean) {
        return postalCodeBeanMapper.insert(postalCodeBean);
    }

    /**
     * 批量新增省市县邮政编码
     *
     * @param postalCodeBeans 省市县邮政编码业务条件
     * @return 受影响行数
     */
    @Override
    public int addPostalCodeOfList(List<PostalCodeBean> postalCodeBeans) {
        return postalCodeBeanMapper.batchInsertByList(postalCodeBeans);
    }

    /**
     * 根据条件修改省市县邮政编码
     *
     * @param postalCodeBean 省市县邮政编码业务条件
     * @return 受影响行数
     */
    @Override
    public int updatePostalCode(PostalCodeBean postalCodeBean) {
        PostalCodeBeanExample postalCodeBeanExample = new PostalCodeBeanExample();
        //使用id和area_no联合修改终到地区名称
        postalCodeBeanExample.createCriteria().andPostNoEqualTo(postalCodeBean.getPostNo()).andIdEqualTo(postalCodeBean.getId());
        //设置修改时间
        postalCodeBean.setUpdateTime(new Date());
        postalCodeBean.setCreateTime(null);
        return postalCodeBeanMapper.updateByExampleSelective(postalCodeBean, postalCodeBeanExample);
    }

    /**
     * 删除单条数据
     *
     * @param paraPostalCodeBean 省市县邮政编码业务条件
     * @return 受影响行数
     */
    @Override
    public int deletePostalCode(ParaPostalCodeBean paraPostalCodeBean) {
        //条件为空时不删除
        if (ObjectUtils.isEmpty(paraPostalCodeBean)) {
            return 0;
        }
        PostalCodeBeanExample postalCodeBeanExample = new PostalCodeBeanExample();
        Criteria criteria = postalCodeBeanExample.createCriteria();
        getSearchData(criteria, paraPostalCodeBean);
        return postalCodeBeanMapper.deleteByExample(postalCodeBeanExample);
    }

    /***
     * 批量删除省市区县邮编信息
     * @param paraPostalCodeBeans 省市县邮政编码业务条件
     * @return 受影响行数
     */
    @Override
    public int deleteReachRegionOfList(List<ParaPostalCodeBean> paraPostalCodeBeans) {
        //判断是否有数据
        if (CollectionUtils.isEmpty(paraPostalCodeBeans)) {
            return 0;
        }
        PostalCodeBeanExample postalCodeBeanExample = new PostalCodeBeanExample();
        Criteria criteria = postalCodeBeanExample.createCriteria();
        Map<Integer, String> conditionMap = new HashMap<>();
        for (ParaPostalCodeBean paraPostalCodeBean : paraPostalCodeBeans) {
            conditionMap.put(paraPostalCodeBean.getId(), paraPostalCodeBean.getPostNo());
        }
        criteria.andIdIn(new ArrayList<>(conditionMap.keySet()));
        return postalCodeBeanMapper.deleteByExample(postalCodeBeanExample);
    }

    /**
     * 从中冠系统同步省市县邮政编码
     *
     * @return同步结果
     */
    @Override
    public APIMsgBean synchronizationZgPostalCode(ZgViewBean zgViewBean) {
        APIMsgBean serviceDataBean = new APIMsgBean();
        //默认失败
        serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("数据同步失败"));
        //参数校验
        String msg = checkData(zgViewBean);
        if (!StringUtils.isBlank(msg)) {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean(msg));
            return serviceDataBean;
        }
        SynZgResult synZgResult = new SynZgResult();
        //同步计时开始
        long begintime = System.currentTimeMillis();
        ZgSOResultBean viewData = zgSOService.getViewData(zgViewBean);
        //同步计时结束
        long endtime = System.currentTimeMillis();
        long costTime = (endtime - begintime);
        //请求中冠成功后
        if ("Y".equals(viewData.getIsSuccess())) {
            List<PostalCodeBean> postalCodeBeans = null;
            try {
                postalCodeBeans = JSONObject.parseArray(viewData.getData(), PostalCodeBean.class);
            } catch (Exception e) {
                serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("终到地区数据同步解析出错"));
                log.error("终到地区数据同步解析出错，错误信息：", e);
            }
            //检查数据库是否有重复,过滤掉重复信息并设置创建、更新、版本信息
            postalCodeBeans = checkDataBase(postalCodeBeans);
            if (!CollectionUtils.isEmpty(postalCodeBeans)) {
                //批量新增
                int i = addPostalCodeOfList(postalCodeBeans);
                if (i > 0) {
                    //设置同步所用时间
                    synZgResult.setSynTime(String.valueOf(costTime));
                    //设置同步条数
                    synZgResult.setCountNum(i);
                    //设置同步状态
                    synZgResult.setState(true);
                    serviceDataBean.setSoaStateBean(ResponseCode.buildEnumSuccessSOAStateBean("数据同步成功"));
                    serviceDataBean.setData(synZgResult);
                    //日志记录
                    log.info("终到地区数据同步成功，本次同步" + i + "条数据,耗时" + costTime + "毫秒");
                }
            } else {
                log.info("无数据同步");
                serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("无数据同步"));
            }
        } else {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean(viewData.getMsg()));
        }
        //递归同步
        try {
            //起始页
            int startPage = Integer.parseInt(zgViewBean.getPageNum());
            //判断是否还有数据
            if (startPage < viewData.getZgpageData().getPages()) {
                startPage++;
                zgViewBean.setPageNum(String.valueOf(startPage));
                synchronizationZgPostalCode(zgViewBean);
            }
        } catch (Exception e) {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("终到地区数据递归同步出错"));
            log.error("终到地区数据递归同步出错，错误信息：", e);
        }
        return serviceDataBean;
    }

    /***
     * 检查数据库中数据是否存在，将不存在的数据返回，过滤掉重复的数据
     * @param postalCodeBeans 需要检查的数据
     * @return List<PostalCodeBean> 不重复的数据
     */
    private List<PostalCodeBean> checkDataBase(List<PostalCodeBean> postalCodeBeans) {
        if (CollectionUtils.isEmpty(postalCodeBeans)) {
            return null;
        }
        PostalCodeBeanExample postalCodeBeanExample = new PostalCodeBeanExample();
        Criteria criteria = postalCodeBeanExample.createCriteria();
        //提取终到地区编码和库中数据做比较，如果重复则判定为重复数据。
        Map<String, PostalCodeBean> postalCodeBeanMap = new HashMap<>();
        for (PostalCodeBean postalCodeBean : postalCodeBeans) {
            postalCodeBeanMap.put(postalCodeBean.getPostNo(), postalCodeBean);
        }
        //查询数据库是否有重复数据
        Set<String> strings = postalCodeBeanMap.keySet();
        ArrayList<String> strings1 = new ArrayList<>(strings);
        criteria.andPostNoIn(strings1);
        List<PostalCodeBean> dbPostalCodeBean = postalCodeBeanMapper.selectByExample(postalCodeBeanExample);
        List<PostalCodeBean> oldPostalCodeBean = new ArrayList<>();
        //比较是否用重复的数据
        for (PostalCodeBean postalCodeBean : dbPostalCodeBean) {
            String postNo = postalCodeBean.getPostNo();
            if (postalCodeBeanMap.containsKey(postNo)) {
                oldPostalCodeBean.add(postalCodeBeanMap.get(postNo));
                postalCodeBeanMap.remove(postNo);
            }
        }
        postalCodeBeans = new ArrayList<>(postalCodeBeanMap.values());
        for (int i = 0; i < postalCodeBeans.size(); i++) {
            postalCodeBeans.get(i).setCreateTime(new Date());
            postalCodeBeans.get(i).setUpdateTime(new Date());
            postalCodeBeans.get(i).setVersionInt(0);
        }
        //当有重复数据是执行同步
        if (!CollectionUtils.isEmpty(oldPostalCodeBean)) {
            postalCodeBeanMap.clear();
            for (PostalCodeBean postalCodeBean : oldPostalCodeBean) {
                postalCodeBeanMap.put(postalCodeBean.getPostNo(), postalCodeBean);
            }
            List<PostalCodeBean> postalCodeBeans1 = equlstDateChange(postalCodeBeanMap);
            if (!CollectionUtils.isEmpty(postalCodeBeans1)) {
                AsynchronousUpDate asynchronousUpDate = new AsynchronousUpDate(postalCodeBeans1);
                new Thread(asynchronousUpDate).start();
            }
        }
        //返回不重复的数据
        return postalCodeBeans;
    }

    /**
     * @param oldPostalCodeBeanMap 重复的数据
     * @return List<PostalCodeBean> 重复且有差异的信息
     * @Description 校验比较返回重复且有差异的的信息
     * @author jia chang bao
     * @date 2020/11/9 17:17
     */
    private List<PostalCodeBean> equlstDateChange(Map<String, PostalCodeBean> oldPostalCodeBeanMap) {
        //如果对象为空就直接结束
        if (oldPostalCodeBeanMap.isEmpty()) {
            return null;
        }
        //条件
        PostalCodeBeanExample postalCodeBeanExample = new PostalCodeBeanExample();
        Criteria criteria = postalCodeBeanExample.createCriteria();
        //将邮政编码作为条件
        Set<String> strings = oldPostalCodeBeanMap.keySet();
        criteria.andPostNoIn(new ArrayList<>(strings));
        //查询出重复的数据用于细致比对
        List<PostalCodeBean> dbPostalCodeBean = postalCodeBeanMapper.selectByExample(postalCodeBeanExample);
        //用来存储重复且有差异的数据
        List<PostalCodeBean> postalCodeBeanList = new ArrayList<>();
        //用数据库中的数据和同步过来的数据进行比较
        for (PostalCodeBean postalCodeBean : dbPostalCodeBean) {
            String postNo = postalCodeBean.getPostNo();
            //如果存在相同的邮政编码
            if (oldPostalCodeBeanMap.containsKey(postNo)) {
                PostalCodeBean postalCodeBeanForMap = oldPostalCodeBeanMap.get(postNo);
                //当省中文名称 或 市县中文名称 数据存在差异时判定为差异数据
                if (!postalCodeBeanForMap.getProvince().equals(postalCodeBean.getProvince()) || !postalCodeBeanForMap.getConty().equals(postalCodeBean.getConty())) {
                    postalCodeBeanForMap.setId(postalCodeBean.getId());
                    postalCodeBeanForMap.setUpdateTime(new Date());
                    postalCodeBeanForMap.setVersionInt(postalCodeBean.getVersionInt() + 1);
                    postalCodeBeanList.add(postalCodeBeanForMap);
                }
            }
        }
        return postalCodeBeanList;
    }

    /**
     * 线程异步修改重复的数
     */
    private class AsynchronousUpDate implements Runnable {
        List<PostalCodeBean> oldPostalCodeBeans;

        public AsynchronousUpDate(List<PostalCodeBean> oldPostalCodeBeans) {
            this.oldPostalCodeBeans = oldPostalCodeBeans;
        }

        @Override
        public void run() {
            //判断是否存在有差异数据，如果有就修改
            try {
                if (!CollectionUtils.isEmpty(oldPostalCodeBeans)) {
                    //记录总需改数据
                    int i = 0;
                    long begintime = System.currentTimeMillis();
                    for (PostalCodeBean postalCodeBean : oldPostalCodeBeans) {
                        i += updatePostalCode(postalCodeBean);
                    }
                    long endtime = System.currentTimeMillis();
                    long costTime = (endtime - begintime);
                    log.info("异步修改地区同步差异信息成功，本次修改" + i + "条数据，耗时" + costTime + "毫秒");
                }
            } catch (Exception e) {
                log.error("同步后的差异数据修改失败，错误原因：", e);
            }
        }
    }

    /**
     * sql拼接
     *
     * @param criteria           sql拼接
     * @param paraPostalCodeBean 参数
     */
    private void getSearchData(Criteria criteria, ParaPostalCodeBean paraPostalCodeBean) {
        // ID
        if (paraPostalCodeBean.getId() != null && paraPostalCodeBean.getId() > 0) {
            criteria.andIdEqualTo(paraPostalCodeBean.getId());
        }
        // 省中文名称
        if (StringUtils.isNotBlank(paraPostalCodeBean.getProvince())) {
            criteria.andProvinceEqualTo(paraPostalCodeBean.getProvince());
        }
        //市县中文名称
        if (StringUtils.isNotBlank(paraPostalCodeBean.getConty())) {
            criteria.andContyEqualTo(paraPostalCodeBean.getConty());
        }
        //创建时间
        if (paraPostalCodeBean.getCreateTime() != null) {
            criteria.andCreateTimeEqualTo(paraPostalCodeBean.getCreateTime());
        }
        //版本号
        if (paraPostalCodeBean.getVersionInt() != null && paraPostalCodeBean.getVersionInt() > 0) {
            criteria.andVersionIntEqualTo(paraPostalCodeBean.getVersionInt());
        }
        //修改时间
        if (paraPostalCodeBean.getUpdateTime() != null) {
            criteria.andUpdateTimeEqualTo(paraPostalCodeBean.getUpdateTime());
        }
    }

    /**
     * 中冠视图请求的参数校验
     *
     * @param zgViewBean 视图名称
     * @return 校验结果
     */
    private String checkData(ZgViewBean zgViewBean) {
        String msg = "";
        if (!StringUtils.isNotBlank(zgViewBean.getMethod())) {
            msg += "请求方法不能为空";
        }
        if (!StringUtils.isNotBlank(zgViewBean.getViewId())) {
            msg += "请求的视图不能为空";
        }
        if (!StringUtils.isNotBlank(zgViewBean.getPageNum())) {
            msg += "请求的页码不能为空";
        }
        return msg;
    }
}
